package handlers

import (
	"encoding/json"
	"github.com/gin-gonic/gin"
	jwt "github.com/golangblogs/gojwt"
	"github.com/gorilla/websocket"
	"log"
	"net/http"
	"path/filepath"
	"zy16/api/request"
	"zy16/dao"
	"zy16/pkg"
)

func Login(c *gin.Context) {
	var data request.LoginReq
	err := c.ShouldBind(&data)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"Code": 500,
			"Msg":  "失败",
			"Data": nil,
		})
		return
	}
	result := dao.Login(data.Tel, pkg.Md5([]byte(data.Password)))
	if result.Id == 0 {
		c.JSON(http.StatusOK, gin.H{
			"Code": 500,
			"Msg":  "没有该用户，已自动注册",
			"Data": dao.Register(data.Tel, pkg.Md5([]byte(data.Password))),
		})
		return
	}

	var claims = pkg.CustomClaims{
		ID: uint(result.Id),
	}
	token, err := jwt.NewJWT("zj").CreateToken(jwt.CustomClaims(claims))
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"Code": 500,
			"Msg":  "token生成失败",
			"Data": nil,
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"Code": 200,
		"Msg":  "Success",
		"Data": token,
	})
}

func Upload(c *gin.Context) {
	file, _ := c.FormFile("file")
	log.Println(file.Filename)
	if file.Size > 500*1024*1024 {
		c.JSON(http.StatusOK, gin.H{
			"Code": 500,
			"Msg":  "只允许上传500M以内的文件",
			"Data": nil,
		})
		return
	}
	ext := filepath.Ext(file.Filename)
	if ext != ".jpg" && ext != ".png" && ext != ".mp4" {
		c.JSON(http.StatusOK, gin.H{
			"Code": 500,
			"Msg":  "文件格式不正确",
			"Data": nil,
		})
		return
	}
	dst := "D:\\gohome\\zy\\zy16\\static\\" + file.Filename
	// 上传文件至指定的完整文件路径
	c.SaveUploadedFile(file, dst)
	img := "/static/" + file.Filename
	c.JSON(http.StatusOK, gin.H{
		"Code": 200,
		"Msg":  "Success",
		"Data": img,
	})
}

func AddArticle(c *gin.Context) {
	var data request.Article
	err := c.ShouldBind(&data)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"Code": 500,
			"Msg":  "失败",
			"Data": nil,
		})
		return
	}
	userId := c.GetUint("userId")
	if data.ArticleType < 1 || data.ArticleType > 3 {
		c.JSON(http.StatusOK, gin.H{
			"Code": 500,
			"Msg":  "只允许发布文本类、图片类、视频类的文章",
			"Data": nil,
		})
		return
	}

	result := dao.AddArticles(data.Title, data.Context, int(userId), data.LikeNum, data.ArticleType)
	c.JSON(http.StatusOK, gin.H{
		"Code": 200,
		"Msg":  "Success",
		"Data": result,
	})
}

func AddFocu(c *gin.Context) {
	var data request.Focu
	err := c.ShouldBind(&data)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"Code": 500,
			"Msg":  "失败",
			"Data": nil,
		})
		return
	}
	userId := c.GetUint("userId")
	result := dao.AddFocu(int(userId), data.FocuId)
	c.JSON(http.StatusOK, gin.H{
		"Code": 200,
		"Msg":  "Success",
		"Data": result,
	})
}

func List(c *gin.Context) {
	userId := c.GetUint("userId")
	result := dao.List(int(userId))
	c.JSON(http.StatusOK, gin.H{
		"Code": 200,
		"Msg":  "Success",
		"Data": result,
	})
}

var OnlineUser = make(map[int]*websocket.Conn)

type WSReq struct {
	Cmd  string      `json:"cmd"`
	Data interface{} `json:"data"`
}

type WSResp struct {
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data"`
}

type SendS struct {
	ToUserId int    `json:"to_user_id"`
	Message  string `json:"message"`
}

type WSSendReq struct {
	Cmd  string `json:"cmd"`
	Data SendS  `json:"data"`
}

func Chat(c *gin.Context) {

	//get middle userId
	userId := c.GetUint("userId")

	// update websocket
	var upgrader = websocket.Upgrader{} // use default options

	conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		log.Print("upgrade:", err)
		c.JSON(http.StatusOK, gin.H{
			"code": -1,
			"msg":  "websocket fail",
			"data": nil,
		})
		return
	}

	defer conn.Close()

	for {
		_, message, err := conn.ReadMessage()
		if err != nil {
			log.Println("read:", err)
			break
		}

		var req WSReq

		err = json.Unmarshal(message, &req)
		if err != nil {

			WSRespErr(conn, 1000, "illegal json")
			continue
		}

		switch req.Cmd {
		case "online":
			go Online(conn, message, int(userId))
		case "send":
			go Send(conn, message)
		default:
			WSRespErr(conn, 10001, "no function")
		}

	}
}

func Send(conn *websocket.Conn, message []byte) {

	var req WSSendReq
	err := json.Unmarshal(message, &req)
	if err != nil {
		WSRespErr(conn, 20001, "Parsing json failed ")
		return
	}

	if OnlineUser[req.Data.ToUserId] == nil {
		WSRespErr(conn, 20003, "not online")
		return
	}

	WSRespSuccess(OnlineUser[req.Data.ToUserId], req.Data.Message)

	WSRespSuccess(conn, "send ok")

}

func Online(conn *websocket.Conn, message []byte, userId int) {

	OnlineUser[userId] = conn
	WSRespSuccess(conn, userId)
}

func WSRespErr(conn *websocket.Conn, code int, msg string) {
	response := WSResp{
		Code: code,
		Msg:  msg,
		Data: nil,
	}

	responseStr, _ := json.Marshal(response)

	err := conn.WriteMessage(websocket.TextMessage, responseStr)
	if err != nil {
		log.Println("write:", err)
	}
}

func WSRespSuccess(conn *websocket.Conn, data interface{}) {
	response := WSResp{
		Code: 0,
		Msg:  "ok",
		Data: data,
	}

	responseStr, _ := json.Marshal(response)

	err := conn.WriteMessage(websocket.TextMessage, responseStr)
	if err != nil {
		log.Println("write:", err)
	}
}
